package pikes.peak;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.junit.Test;
import pikes.ecma.FunctionCall;
import pikes.ecma.IndexedAccess;
import pikes.ecma.MemberPropertyAccess;
import pikes.ecma.SourceElements;
import pikes.html.xhtml.Flow;
import pikes.html.xhtml.Inline;
import pikes.html.xhtml.PCData;
import pikes.html.xhtml.form.Option;
import pikes.html.xhtml.form.Select;
import pikes.peak.ComboBox;
import pikes.peak.ObjectFormatter;
import pikes.peak.RequestProperty;
import pikes.peak.test.AssertHtml;
import pikes.peak.test.PikesPeakComponentTestCase;

import org.springframework.web.servlet.support.RequestContext;

public class ComboboxTestCase extends PikesPeakComponentTestCase {

	@Test
	public void defineEmptyCombobox() throws Exception {
		ComboBox cb = new ComboBox();

		Select expected = new Select(new Option());

		Flow actual = cb.createHtml(new HashMap(), pikesPeakRequest.getRequestContext());
		AssertHtml.assertEquals(expected, actual);
	}

	@Test
	public void defineEmptyComboboxWithName() throws Exception {
		ComboBox cb = new ComboBox("name");

		Select expected = new Select(new Option());
		expected.setName("name");

		Flow actual = cb.createHtml(new HashMap(), pikesPeakRequest.getRequestContext());
		AssertHtml.assertEquals(expected, actual);
	}

	@Test
	public void defineComboboxWithNullOptionList() throws Exception {
		ComboBox cb = new ComboBox(new RequestProperty<Collection<Object>>() {

			public Collection<Object> getValue(Map model, RequestContext rc) throws Exception {
				return null;
			}
		});

		Select expected = new Select(new Option());

		Flow actual = cb.createHtml(new HashMap(), pikesPeakRequest.getRequestContext());
		AssertHtml.assertEquals(expected, actual);
	}

	@Test
	public void defineComboboxWithOneOption() throws Exception {
		final Object object = new Object();

		ComboBox cb = new ComboBox(new RequestProperty<Collection<Object>>() {

			public Collection<Object> getValue(Map model, RequestContext rc) throws Exception {
				ArrayList<Object> array = new ArrayList<Object>();
				array.add(object);
				return array;
			}
		});

		Select expected = new Select(new Option(object.toString(), object.toString()));

		Flow actual = cb.createHtml(new HashMap(), pikesPeakRequest.getRequestContext());
		AssertHtml.assertEquals(expected, actual);
	}

	@Test
	public void defineComboboxWith2Options() throws Exception {
		final Object object1 = new Object();
		final Object object2 = new Object();

		ComboBox cb = new ComboBox(new RequestProperty<Collection<Object>>() {

			public Collection<Object> getValue(Map model, RequestContext rc) throws Exception {
				ArrayList<Object> array = new ArrayList<Object>();
				array.add(object1);
				array.add(object2);
				return array;
			}
		});

		Select expected = new Select(new Option(object1.toString(), object1.toString()));
		expected.add(new Option(object2.toString(), object2.toString()));

		Flow actual = cb.createHtml(new HashMap(), pikesPeakRequest.getRequestContext());
		AssertHtml.assertEquals(expected, actual);
	}

	@Test
	public void defineComboboxWith2OptionsFirstSelected() throws Exception {
		final Object object1 = new Object();
		final Object object2 = new Object();

		ComboBox cb = new ComboBox(new RequestProperty<Collection<Object>>() {

			public Collection<Object> getValue(Map model, RequestContext rc) throws Exception {
				ArrayList<Object> array = new ArrayList<Object>();
				array.add(object1);
				array.add(object2);
				return array;
			}
		});

		cb.setSelectedObjectProvider(new RequestProperty<Object>() {

			public Object getValue(Map model, RequestContext requestContext) throws Exception {
				return object1;
			}

		});

		Select expected = new Select(new Option(object1.toString(), object1.toString(), true));
		expected.add(new Option(object2.toString(), object2.toString()));

		Flow actual = cb.createHtml(new HashMap(), pikesPeakRequest.getRequestContext());
		AssertHtml.assertEquals(expected, actual);
	}

	@Test
	public void defineComboboxWithOneOptionAndFormat() throws Exception {
		final MockObject object = new MockObject("mockId", "mockName");

		ComboBox<MockObject> cb = new ComboBox<MockObject>(new RequestProperty<Collection<MockObject>>() {

			public Collection<MockObject> getValue(Map model, RequestContext rc) throws Exception {
				ArrayList<MockObject> array = new ArrayList<MockObject>();
				array.add(object);
				return array;
			}
		});

		cb.setFormatter(new ObjectFormatter<MockObject>() {

			public CharSequence getValue(MockObject object, Map model, RequestContext requestContext) {
				return object.getId();
			}

			public Inline getLabel(MockObject object, Map model, RequestContext requestContext) {
				return new PCData(object.getName());
			}
		});

		Select expected = new Select(new Option("mockId", "mockName"));

		Flow actual = cb.createHtml(new HashMap(), pikesPeakRequest.getRequestContext());
		AssertHtml.assertEquals(expected, actual);
	}

	@Test
	public void defineEmptyComboboxWithOnChange() throws Exception {
		ComboBox<Object> cb = new ComboBox<Object>();

		SourceElements elements = new SourceElements();
		elements.add(new FunctionCall(new MemberPropertyAccess(new IndexedAccess(new MemberPropertyAccess("document",
				"forms"), "0"), "submit")));
		cb.setOnChange(elements);

		Select expected = new Select(new Option());
		expected.setOnChange("document.forms[0].submit();");

		Flow actual = cb.createHtml(new HashMap(), pikesPeakRequest.getRequestContext());
		AssertHtml.assertEquals(expected, actual);
	}
}

class MockObject {

	private String name = null;

	private String id = null;

	public MockObject(String id, String name) {
		super();
		this.name = name;
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public String getId() {
		return id;
	}
}